package com.atguigu.yygh.hosp.aop.advice;

import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import com.atguigu.yygh.common.exception.YyghException;
import com.atguigu.yygh.hosp.annotation.SecureValid;
import com.atguigu.yygh.hosp.service.HospitalSetService;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;

/**
 * @author 孔德成
 * @slogan 致敬大师，致敬未来的你
 * @date 2021/9/4 8:11 上午
 * @desc 签名校验
 */
@Aspect
@Component
public class SignatureVerificationAdvice {

    private final HospitalSetService hospitalSetService;

    public SignatureVerificationAdvice(HospitalSetService hospitalSetService) {
        this.hospitalSetService = hospitalSetService;
    }

    /**
     * 签名校验通知，限制匹配添加了 @SecureValid 注解的 ApiController 中的方法
     *
     * @param pjp 通过该参数来调用被通知的方法
     * @param is  切点参数
     */
    @Around("apiController() && @annotation(is)")
    public Object doAccessControl(ProceedingJoinPoint pjp, SecureValid is)
            throws Throwable {
        // 获取所有参数
        Object[] args = pjp.getArgs();
        // 获取 Request 参数
        HttpServletRequest request = (HttpServletRequest) args[0];

        // 获取医院编号和医院签名
        String hoscode = request.getParameter("hoscode");
        String sign = request.getParameter("sign");


        // 没有必要参数，快速响应失败
        if (StrUtil.isBlank(sign) || StrUtil.isBlank(hoscode)) {
            throw new YyghException(20001, "签名错误");
        }

        // 调用医院设置业务接口，根据医院编号获取签名
        String signKey = hospitalSetService.getSignKey(hoscode);

        // 对签名进行校验
        if (!sign.equals(SecureUtil.md5(signKey))) {
            throw new YyghException(20001, "签名错误");
        }
        // 执行业务
        return pjp.proceed();
    }

    /**
     * 声明切点，匹配 ApiController 的所有方法
     */
    @Pointcut("execution(* com.atguigu.yygh.hosp.controller.ApiController.*(..))")
    public void apiController() {
    }
}
